/*
    socklibpp library
    Copyright (C) 2005  Daniel K. O. <danielosmari at users.sf.net>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#pragma warning( disable : 4290 )


#ifndef SOCK_ADDR_H
#define SOCK_ADDR_H


/**     \file   sockaddr.h
        \brief  Classes for handling addresses
*/


#include <stdexcept>
#include <ostream>
#include <istream>
#include <string>

#include "sockcommon.h"

namespace socklib {

/**     \brief  Abstract base class for network addresses.
*/
class addr {

        struct sockaddr *_M_data;

protected:
        /// This holds the data size.
        int _M_size;

        /// Constructor that sets the internal pointer and size
        addr(struct sockaddr * _d, int _s) throw() :
                _M_data(_d),
                _M_size(_s)
        { }
        
        virtual
        ~addr() {}

        /// Resets the size of the internal sockaddr reprentation
        virtual void reset() throw() = 0;

        friend class base;
        
public:

        /// Address families
        enum family {
                af_unspec       = AF_UNSPEC,    ///< Unspecified
                af_unix         = AF_UNIX,      ///< Unix (pipes)
                af_inet         = AF_INET,      ///< IPv4
                af_inet6        = AF_INET6,     ///< IPv6
                af_max          = AF_MAX
        };


        /// Returns a pointer to the sockaddr representation
        struct sockaddr *
        data() { return _M_data; }

        /// Returns a read-only pointer to the sockaddr representation
        const struct sockaddr *
        data() const { return _M_data; }

        /// Returns the size of the sockaddr representation
        int
        size() const { return _M_size; }
        
        /// Sets the size of the sockaddr representation
        void
        size(int _size) { _M_size = _size; }
};


/**     \brief  Derived class for handling IPv4 addesses.

        All the integer values handled by the class user are in host-byte-order.
*/
class addr_in : public addr {

        struct sockaddr_in _M_addr;     // for IPv4

        static bool is_ascii_string(const std::string&) throw();

protected:
        /// Resets the internal size to the correct value
        virtual void reset() throw();

public:
        /// Default IPv4 addresses
        enum address {
                addr_any        = INADDR_ANY,           ///< Any
                addr_loopback   = INADDR_LOOPBACK,      ///< Loopback
                addr_broadcast  = INADDR_BROADCAST,     ///< Broadcast
                addr_none       = INADDR_NONE           ///< None
        };


        /// Default constructor
        addr_in() throw();

        /// Constructor taking a default address and a port
        addr_in(address _addr, uint16_t _port) throw();

        /// Constructor taking an address and a port
        addr_in(uint32_t _addr, uint16_t _port) throw();

        /// Constructor taking a string argument and a port
        addr_in(const std::string&, uint16_t) throw (std::invalid_argument);

        /// Constructor taking a string argument
        addr_in(const std::string&) throw (std::invalid_argument);
        
        /// Validates a string to see if has the correct "X.X.X.X" format
        static bool validate_addr(const std::string&) throw();
        
        /// Validates a string to see if has the correct "X.X.X.X:P" format
        static bool validate_addr_port(const std::string&) throw();
        
        
        /// Resolves a host name
        bool resolve(const std::string&) throw();

        /// Convenience method that calls resolve() and port()
        bool resolve_port(const std::string&) throw();
        
        /// Convenience method that calls resolve() and port()
        bool resolve_port(const std::string&, uint16_t) throw();

        /// Get the port
        inline uint16_t
        port() const throw () { return ntohs(_M_addr.sin_port); }

        /// Set the port
        void
        port(uint16_t _port) throw () { _M_addr.sin_port = htons(_port); }
        
        /// Set the port using a service name and a protocol name
        bool
        port(const std::string&, const std::string&) throw();

        /// Set the port using a service name
        bool
        port(const std::string&) throw();

        /// Get the ip
        inline uint32_t
        ip() const throw()
        {       uint32_t _temp;
                std::memcpy(&_temp, &_M_addr.sin_addr, 4);
                return ntohl(_temp);
        }
        
        /// Set the ip
        inline void
        ip(uint32_t _host) throw()
        {
                _host = htonl(_host);
                std::memcpy(&_M_addr.sin_addr, &_host, 4);
        }


        /// Set the ip using a string
        bool
        ip(const std::string&) throw();


        /**     \brief Convenience method that wraps ip() and port()
                \sa ip(), port()
        */
        bool
        ip_port(const std::string&, uint16_t) throw();
        

        /// Convenience method that wraps ip() and port()
        bool
        ip_port(const std::string&) throw();


        friend
        std::ostream& operator<<(std::ostream&, const addr_in&);
        
        friend
        std::istream& operator>>(std::istream&, addr_in&);
};

/// Operator for printing an address in a stream
std::ostream& operator<<(std::ostream&, const addr_in&);

/// Operator for reading an address from a stream
std::istream& operator>>(std::istream&, addr_in&);

}


#endif
